package main

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"math/big"
)

type ProofOfWork struct {
	block *Block

	// 目标值
	target *big.Int
}

// POW构造函数
func NewProofOfWork(block *Block) *ProofOfWork {
	pow := ProofOfWork{
		block: block,
	}

	//我们指定的难度值，现在是一个string类型，需要进行转换
	targetStr := "0000f00000000000000000000000000000000000000000000000000000000000"
	tempInt := big.Int{}
	tempInt.SetString(targetStr, 16)
	pow.target = &tempInt
	return &pow
}

// 不断计算hash,并比较
func (pow *ProofOfWork) Run() ([]byte, uint64) {
	block := pow.block
	var hash [32]byte
	var nonce uint64
	fmt.Printf("开始挖矿... \n")
	//log.Panic("开始挖矿... \n")
	for {
		temp := [][]byte{
			Uint64ToByte(block.Version),
			block.PreHash,
			block.MerkelRoot,
			Uint64ToByte(block.TimeStamp),
			Uint64ToByte(block.Difficulty),
			Uint64ToByte(nonce),
			block.Data,
		}
		blockInfo := bytes.Join(temp, []byte{})
		hash = sha256.Sum256(blockInfo)
		tempInt := big.Int{}
		tempInt.SetBytes(hash[:])
		// 比较计算的 hash 和 target
		if tempInt.Cmp(pow.target) == -1 {
			fmt.Printf("挖矿成功！hash : %x, nonce : %d\n", hash, nonce)
			return hash[:], nonce
		} else {
			nonce++
		}
	}
}
